home *** CD-ROM | disk | FTP | other *** search
- /*
- File: iTVPlugIn.c
-
- Contains: visual plug-in for iTunes
-
- Written by: Developer Technical Support
-
- Copyright: Copyright ©2001 Apple Computer,Inc.
-
- Change History (most recent first):
-
- <1> 4/17/01 DTS first checked in.
- */
-
- /**\
- |**| includes
- \**/
-
- #include "iTunesVisualAPI.h"
- #include <CGRemoteOperation.h>
-
- /**\
- |**| typedef's, struct's, enum's, etc.
- \**/
-
- #define kTVisualPluginName "\pDockDancePlugIn"
- #define kTVisualPluginCreator 'hook'
-
- #define kTVisualPluginMajorVersion 1
- #define kTVisualPluginMinorVersion 0
- #define kTVisualPluginReleaseStage finalStage
- #define kTVisualPluginNonFinalRelease 0
- #define kStart 10
- static Rect gDockRect;
- static Boolean gStop = true;
-
- CGEventErr (*CGPostMouseEventFctPtr) ( CGPoint, boolean_t, CGButtonCount, boolean_t, ...) =0;
-
- CGEventErr (*CGSetLocalEventsSuppressionIntervalFctPtr)(CFTimeInterval seconds) = 0;
- void (*CGContextFillRectsFctPtr)(CGContextRef,const CGRect [],size_t) = 0;
- void (*CGContextSetRGBFillColorFctPtr)(CGContextRef, float, float, float, float)=0;
- void (*CGContextFlushFctPtr)(CGContextRef ctx) = 0;
- void (*CGContextScaleCTMFctPtr)( CGContextRef ctx, float sx, float sy) =0;
- void (*CGContextTranslateCTMFctPtr)( CGContextRef ctx, float sx, float sy) =0;
- void (*CGContextRotateCTMFctPtr)( CGContextRef ctx, float sx) =0;
-
- typedef struct VisualPluginData {
- void * appCookie;
- ITAppProcPtr appProc;
-
- ITFileSpec pluginFileSpec;
-
- CGrafPtr destPort;
- Rect destRect;
- CGContextRef destContext;
- OptionBits destOptions;
- UInt32 destBitDepth;
-
- RenderVisualData renderData;
- UInt32 renderTimeStampID;
-
- ITTrackInfo trackInfo;
- ITStreamInfo streamInfo;
-
- Boolean playing;
- Boolean padding[3];
-
- // Plugin-specific data
-
- GWorldPtr offscreen;
- UInt32 position;
- Boolean idling;
- UInt32 previousMaxIndex;
- UInt32 currentMaxIndex;
- UInt32 previousMaxValue;
- UInt32 currentMaxValue;
- } VisualPluginData;
-
-
- #define SET_PIXEL(pm,h,v,c) \
- { RGBForeColor(c);MoveTo(h,v);Line(1,0);}
-
- /**\
- |**| local (static) globals
- \**/
-
- static CGrafPtr gSavePort;
- static GDHandle gSaveDevice;
- static SInt16 gLine = 0;
- static CFBundleRef gCGBundle =0;
- static float values[kVisualNumSpectrumEntries];
-
- /**\
- |**| exported function prototypes
- \**/
-
- extern OSStatus iTunesPluginMain(OSType message,PluginMessageInfo *messageInfo,void *refCon);
-
- /**\
- |**| static functions
- \**/
-
- // MemClear
- static void MemClear(LogicalAddress dest,SInt32 length)
- {
- register unsigned char *ptr;
-
- ptr = (unsigned char*) dest;
-
- while (length-- > 0)
- *ptr++ = 0;
- }
-
- void InitCoreGraphicFunctions()
- {
- gCGBundle = CFBundleGetBundleWithIdentifier( CFSTR("com.apple.CoreGraphics"));
-
- CGPostMouseEventFctPtr = (CGEventErr(*)( CGPoint, boolean_t, CGButtonCount, boolean_t, ...))
- CFBundleGetFunctionPointerForName(gCGBundle, CFSTR("CGPostMouseEvent"));
-
- CGSetLocalEventsSuppressionIntervalFctPtr = (CGEventErr(*)( CFTimeInterval))
- CFBundleGetFunctionPointerForName(gCGBundle, CFSTR("CGSetLocalEventsSuppressionInterval"));
-
- CGContextFillRectsFctPtr = (void(*)( CGContextRef,const CGRect [],size_t))
- CFBundleGetFunctionPointerForName(gCGBundle, CFSTR("CGContextFillRects"));
-
- CGContextSetRGBFillColorFctPtr = (void (*)(CGContextRef, float, float, float, float))
- CFBundleGetFunctionPointerForName(gCGBundle, CFSTR("CGContextSetRGBFillColor"));
-
- CGContextFlushFctPtr = (void (*)(CGContextRef ctx) )
- CFBundleGetFunctionPointerForName(gCGBundle, CFSTR("CGContextFlush"));
-
- CGContextTranslateCTMFctPtr = (void (*)(CGContextRef, float, float))
- CFBundleGetFunctionPointerForName(gCGBundle, CFSTR("CGContextTranslateCTM"));
- CGContextRotateCTMFctPtr = (void (*)(CGContextRef, float))
- CFBundleGetFunctionPointerForName(gCGBundle, CFSTR("CGContextRotateCTM"));
- CGContextScaleCTMFctPtr = (void (*)(CGContextRef, float, float))
- CFBundleGetFunctionPointerForName(gCGBundle, CFSTR("CGContextScaleCTM"));
-
-
- }
-
- // ProcessRenderData
-
- void ProcessRenderData(VisualPluginData *visualPluginData,const RenderVisualData *renderData)
- {
- SInt16 index;
- SInt32 channel;
-
- if (renderData == nil)
- {
- MemClear(&visualPluginData->renderData,sizeof(visualPluginData->renderData));
- return;
- }
-
- visualPluginData->renderData = *renderData;
-
- visualPluginData->previousMaxIndex = visualPluginData->currentMaxIndex;
- visualPluginData->previousMaxValue = visualPluginData->currentMaxValue;
-
- for (channel = 0;channel < renderData->numSpectrumChannels;channel++)
- {
- visualPluginData->currentMaxValue = renderData->spectrumData[channel][0];
- visualPluginData->currentMaxIndex = 0;
- for (index = 1; index < kVisualNumSpectrumEntries; index++)
- {
- UInt8 value;
- value = renderData->spectrumData[channel][index];
-
- if (value > visualPluginData->currentMaxValue)
- {
- visualPluginData->currentMaxValue = value;
- visualPluginData->currentMaxIndex = index;
- }
- }
- }
-
- }
-
- /*
- RenderVisualPort
- */
- void RenderVisualPort(VisualPluginData *visualPluginData, Boolean playing)
- {
-
- CGrafPtr port;
- static CGContextRef context = NULL;
- GDHandle dev;
- UInt32 spectIndex;
- RgnHandle rgn;
- RGBColor black = {0,0,0};
- CGRect rects[32];
- long index;
- CGRect baseRect = {{0,0}, {0,0}};
- Rect bounds = visualPluginData->destRect;
- UInt32 width;
-
- static float directionX = 1;
- static float directionY = 1;
- static float angle = 2;
- static float scalingX = 0.9;
- static float scalingY = 0.9;
-
- long change = TickCount();
-
- if (context == NULL)
- CreateCGContextForPort(visualPluginData->destPort,&context);
-
- if (context == NULL)
- return;
-
- /*
- if (change % 2)
- directionX = -directionX;
-
- if (change % 3)
- directionY = -directionY;
-
- if (change % 7)
- angle = -angle;
-
- if (change % 13)
- scalingX *= 0.3;
-
- if (change % 3)
- scalingX = 0.9;
-
- if (change % 2)
- scalingY *= 0.3;
-
- if (change % 11)
- scalingY = 0.9;
-
-
- CGContextTranslateCTMFctPtr(context, directionX, directionY);
- CGContextRotateCTMFctPtr(context, angle);
- CGContextScaleCTMFctPtr(context, scalingX, scalingY);
- */
- if( visualPluginData->playing == false)
- return;
-
- GetGWorld(&port, &dev);
- SetPort(visualPluginData->destPort);
- RGBBackColor(&black);
- EraseRect(&visualPluginData->destRect);
- SetGWorld(port, dev);
-
- rgn = NewRgn();
- RectRgn( rgn,&visualPluginData->destRect);
- ClipCGContextToRegion(context,& visualPluginData->destRect, rgn);
- DisposeRgn(rgn);
-
-
- width = (bounds.right - bounds.left) / 32;
-
- baseRect.origin.x = 10;
- baseRect.origin.y = 40;
- baseRect.size.width = width;
-
- for (spectIndex = 0, index =0; spectIndex < kVisualNumSpectrumEntries; spectIndex+= (kVisualNumSpectrumEntries/32), index++)
- {
- UInt8 value;
- baseRect.origin.x += width;
-
- value = visualPluginData->renderData.spectrumData[0][spectIndex];
-
- baseRect.size.height = (((float)value)/255.0) * (bounds.bottom - bounds.top-20);
-
- rects[index].origin.x = baseRect.origin.x;
- rects[index].origin.y = baseRect.origin.y;
- rects[index].size.width = baseRect.size.width;
- rects[index].size.height = baseRect.size.height;
-
- }
-
-
- CGContextSetRGBFillColorFctPtr(context, 0,1,0,1);
- CGContextFillRectsFctPtr(context, rects, 30);
- CGContextFlushFctPtr(context);
-
- if (CGPostMouseEventFctPtr == NULL)
- return;
-
- if (gStop == true)
- return;
-
- if (playing == true)
- {
- static float invert = 0;
-
- if ((visualPluginData->currentMaxIndex == visualPluginData->previousMaxIndex) &&
- (visualPluginData->currentMaxValue < visualPluginData->previousMaxValue))
- {
- CGPoint pos;
- pos.x = 0;
- pos.y = 0;
-
- // CGPostMouseEventFctPtr(pos,true, 1, false );
- }
- else
- {
- CGPoint pos;
- if ( visualPluginData->currentMaxIndex != visualPluginData->previousMaxIndex )
- values[visualPluginData->previousMaxIndex] = 0;
-
- values[visualPluginData->currentMaxIndex] += visualPluginData->currentMaxValue/2;
-
- pos.x = (invert-(((float)(visualPluginData->currentMaxIndex))/((float)kVisualNumSpectrumEntries)) )
- * (gDockRect.right-500)+250;
-
- if (values[visualPluginData->currentMaxIndex] < 128)
- {
- pos.y = gDockRect.bottom-10;
- }
- else
- {
- pos.y = gDockRect.bottom-138;
-
- if (invert == 0)
- invert = 1;
- else
- invert = 0;
- }
-
- CGPostMouseEventFctPtr(pos,true, 1, false );
- }
-
- }
- else
- {
- static SInt8 direction = 30;
-
- if ((visualPluginData->position > (gDockRect.right-kStart)))
- direction = -direction;
-
- if (visualPluginData->position < (gDockRect.left+kStart))
- {
- direction = -direction;
- visualPluginData->position = (gDockRect.left+kStart);
- }
-
- {
- CGPoint pos;
- pos.x = visualPluginData->position;
- pos.y = gDockRect.bottom-10;
-
-
- CGPostMouseEventFctPtr(pos,true, 1, false );
- }
-
-
-
-
- visualPluginData->position += direction;
- }
- }
-
- /*
- ResetRenderData
- */
- static void ResetRenderData(VisualPluginData *visualPluginData)
- {
- MemClear(&visualPluginData->renderData,sizeof(visualPluginData->renderData));
-
- visualPluginData->previousMaxIndex = visualPluginData->currentMaxIndex = 0;
- }
-
- /*
- VisualPluginHandler
- */
- OSStatus VisualPluginHandler(OSType message,VisualPluginMessageInfo *messageInfo,void *refCon)
- {
- OSStatus status;
- VisualPluginData * visualPluginData;
-
- visualPluginData = (VisualPluginData*) refCon;
-
- status = noErr;
-
- switch (message)
- {
- /*
- Sent when the visual plugin is registered. The plugin should do minimal
- memory allocations here. The resource fork of the plugin is still available.
- */
- case kVisualPluginInitMessage:
- {
- visualPluginData = (VisualPluginData*) NewPtrClear(sizeof(VisualPluginData));
- if (visualPluginData == nil)
- {
- status = memFullErr;
- break;
- }
-
- visualPluginData->appCookie = messageInfo->u.initMessage.appCookie;
- visualPluginData->appProc = messageInfo->u.initMessage.appProc;
-
- /* Remember the file spec of our plugin file. We need this so we can open our resource fork during */
- /* the configuration message */
-
- status = PlayerGetPluginFileSpec(visualPluginData->appCookie,visualPluginData->appProc,&visualPluginData->pluginFileSpec);
-
- messageInfo->u.initMessage.refCon = (void*) visualPluginData;
- break;
- }
-
- /*
- Sent when the visual plugin is unloaded
- */
- case kVisualPluginCleanupMessage:
- if (visualPluginData != nil)
- DisposePtr((Ptr)visualPluginData);
- break;
-
- /*
- Sent when the visual plugin is enabled. iTunes currently enables all
- loaded visual plugins. The plugin should not do anything here.
- */
- case kVisualPluginEnableMessage:
- case kVisualPluginDisableMessage:
- break;
-
- /*
- Sent if the plugin requests idle messages. Do this by setting the kVisualWantsIdleMessages
- option in the RegisterVisualMessage.options field.
- */
- case kVisualPluginIdleMessage:
- RenderVisualPort(visualPluginData, visualPluginData->playing);
- break;
-
- /*
- Sent when iTunes is going to show the visual plugin in a port. At
- this point,the plugin should allocate any large buffers it needs.
- */
- case kVisualPluginShowWindowMessage:
- visualPluginData->destOptions = messageInfo->u.showWindowMessage.options;
- visualPluginData->destPort = messageInfo->u.showWindowMessage.port;
- visualPluginData->destRect = messageInfo->u.showWindowMessage.drawRect;
-
- break;
-
- /*
- Sent when iTunes is no longer displayed.
- */
- case kVisualPluginHideWindowMessage:
-
- MemClear(&visualPluginData->trackInfo,sizeof(visualPluginData->trackInfo));
- MemClear(&visualPluginData->streamInfo,sizeof(visualPluginData->streamInfo));
- break;
-
- /*
- Sent when iTunes needs to change the port or rectangle of the currently
- displayed visual.
- */
- case kVisualPluginSetWindowMessage:
- visualPluginData->destOptions = messageInfo->u.setWindowMessage.options;
- visualPluginData->destPort = messageInfo->u.showWindowMessage.port;
- visualPluginData->destRect = messageInfo->u.showWindowMessage.drawRect;
-
- break;
-
- /*
- Sent for the visual plugin to render a frame.
- */
- case kVisualPluginRenderMessage:
- visualPluginData->renderTimeStampID = messageInfo->u.renderMessage.timeStampID;
- ProcessRenderData(visualPluginData,messageInfo->u.renderMessage.renderData);
-
- RenderVisualPort(visualPluginData,visualPluginData->playing);
- break;
-
- /*
- Sent in response to an update event. The visual plugin should update
- into its remembered port. This will only be sent if the plugin has been
- previously given a ShowWindow message.
- */
- case kVisualPluginUpdateMessage:
- break;
-
- /*
- Sent when the player starts.
- */
- case kVisualPluginPlayMessage:
- if (messageInfo->u.playMessage.trackInfo != nil)
- visualPluginData->trackInfo = *messageInfo->u.playMessage.trackInfo;
- else
- MemClear(&visualPluginData->trackInfo,sizeof(visualPluginData->trackInfo));
-
- if (messageInfo->u.playMessage.streamInfo != nil)
- visualPluginData->streamInfo = *messageInfo->u.playMessage.streamInfo;
- else
- MemClear(&visualPluginData->streamInfo,sizeof(visualPluginData->streamInfo));
-
- visualPluginData->playing = true;
- HideCursor();
- break;
-
- /*
- Sent when the player changes the current track information. This
- is used when the information about a track changes,or when the CD
- moves onto the next track. The visual plugin should update any displayed
- information about the currently playing song.
- */
- case kVisualPluginChangeTrackMessage:
- if (messageInfo->u.changeTrackMessage.trackInfo != nil)
- visualPluginData->trackInfo = *messageInfo->u.changeTrackMessage.trackInfo;
- else
- MemClear(&visualPluginData->trackInfo,sizeof(visualPluginData->trackInfo));
-
- if (messageInfo->u.changeTrackMessage.streamInfo != nil)
- visualPluginData->streamInfo = *messageInfo->u.changeTrackMessage.streamInfo;
- else
- MemClear(&visualPluginData->streamInfo,sizeof(visualPluginData->streamInfo));
- break;
-
- /*
- Sent when the player stops.
- */
- case kVisualPluginStopMessage:
- visualPluginData->playing = false;
- ResetRenderData(visualPluginData);
- visualPluginData->position = 512;
-
- RenderVisualPort(visualPluginData,visualPluginData->playing);
- ShowCursor();
- break;
-
- /*
- Sent when the player changes position.
- */
- case kVisualPluginSetPositionMessage:
- break;
-
- /*
- Sent when the player pauses. iTunes does not currently use pause or unpause.
- A pause in iTunes is handled by stopping and remembering the position.
- */
- case kVisualPluginPauseMessage:
- visualPluginData->playing = false;
-
- ResetRenderData(visualPluginData);
- visualPluginData->position = 512;
-
- RenderVisualPort(visualPluginData,visualPluginData->playing);
- ShowCursor();
- break;
-
- /*
- Sent when the player unpauses. iTunes does not currently use pause or unpause.
- A pause in iTunes is handled by stopping and remembering the position.
- */
- case kVisualPluginUnpauseMessage:
- visualPluginData->playing = true;
-
- break;
-
- /*
- Sent to the plugin in response to a MacOS event. The plugin should return noErr
- for any event it handles completely,or an error (unimpErr) if iTunes should handle it.
- */
- case kVisualPluginEventMessage:
- {
- EventRecord* tEventPtr = messageInfo->u.eventMessage.event;
- if ((tEventPtr->what == keyDown) || (tEventPtr->what == autoKey))
- { // charCodeMask,keyCodeMask;
- char theChar = tEventPtr->message & charCodeMask;
-
- switch (theChar)
- {
- case 'q':
- case 'Q':
- gStop = !gStop;
- status = noErr;
- break;
- case 'f':
- case 'F':
- status = noErr;
- break;
- default:
- status = unimpErr;
- break;
- }
- }
- else
- status = unimpErr;
- }
- break;
-
- default:
- status = unimpErr;
- break;
- }
- return status;
- }
-
- /*
- RegisterVisualPlugin
- */
- OSStatus RegisterVisualPlugin(PluginMessageInfo *messageInfo)
- {
- OSStatus status;
- PlayerMessageInfo playerMessageInfo;
- Str255 pluginName = kTVisualPluginName;
-
- MemClear(&playerMessageInfo.u.registerVisualPluginMessage,sizeof(playerMessageInfo.u.registerVisualPluginMessage));
-
- BlockMoveData((Ptr)&pluginName[0],(Ptr)&playerMessageInfo.u.registerVisualPluginMessage.name[0],pluginName[0] + 1);
-
- SetNumVersion(&playerMessageInfo.u.registerVisualPluginMessage.pluginVersion,kTVisualPluginMajorVersion,kTVisualPluginMinorVersion,kTVisualPluginReleaseStage,kTVisualPluginNonFinalRelease);
-
- playerMessageInfo.u.registerVisualPluginMessage.options = 0;//kVisualWantsIdleMessages ;
- playerMessageInfo.u.registerVisualPluginMessage.handler = VisualPluginHandler;
- playerMessageInfo.u.registerVisualPluginMessage.registerRefCon = 0;
- playerMessageInfo.u.registerVisualPluginMessage.creator = kTVisualPluginCreator;
-
- playerMessageInfo.u.registerVisualPluginMessage.timeBetweenDataInMS = 0xF; // 16 milliseconds = 1 Tick,0xFFFFFFFF = Often as possible.
- playerMessageInfo.u.registerVisualPluginMessage.numWaveformChannels = 2;
- playerMessageInfo.u.registerVisualPluginMessage.numSpectrumChannels = 2;
-
- playerMessageInfo.u.registerVisualPluginMessage.minWidth = 64;
- playerMessageInfo.u.registerVisualPluginMessage.minHeight = 64;
- playerMessageInfo.u.registerVisualPluginMessage.maxWidth = 32767;
- playerMessageInfo.u.registerVisualPluginMessage.maxHeight = 32767;
- playerMessageInfo.u.registerVisualPluginMessage.minFullScreenBitDepth = 0;
- playerMessageInfo.u.registerVisualPluginMessage.maxFullScreenBitDepth = 0;
- playerMessageInfo.u.registerVisualPluginMessage.windowAlignmentInBytes = 0;
-
- status = PlayerRegisterVisualPlugin(messageInfo->u.initMessage.appCookie,messageInfo->u.initMessage.appProc,&playerMessageInfo);
-
-
-
- return status;
-
- }
-
- /**\
- |**| main entrypoint
- \**/
-
- OSStatus iTunesPluginMain(OSType message,PluginMessageInfo *messageInfo,void *refCon)
- {
- OSStatus status;
-
- (void) refCon;
-
- switch (message)
- {
- case kPluginInitMessage:
- {
- Rect avail;
- GDHandle screen = GetMainDevice();
-
- status = RegisterVisualPlugin(messageInfo);
-
- MemClear(values, sizeof(values));
-
- InitCoreGraphicFunctions();
-
- CGSetLocalEventsSuppressionIntervalFctPtr(1.0/50.0);
- GetAvailableWindowPositioningBounds(screen,&avail);
- SetRect(&gDockRect, (*screen)->gdRect.left, avail.bottom,
- (*screen)->gdRect.right, (*screen)->gdRect.bottom);
- break;
- }
- case kPluginCleanupMessage:
- CFRelease(gCGBundle);
- status = noErr;
- break;
-
- default:
- status = unimpErr;
- break;
- }
-
- return status;
- }
-